// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef __PLANETARYPAGE_H_
#define __PLANETARYPAGE_H_

#include "planetaryloadable.h"
#include "planetarypagerenderable.h"
#include "planetarypagelodjoint.h"
#include <OgreSceneNode.h>
#include <vector>

namespace Ogre
{
	class PlanetaryTile;
	class PlanetaryOptions;
	class PlanetarySceneManager;
	class PlanetaryZone;

	/**
	 * Manages a page in the renderable world.
	 * A page gets created from the parent zone, as is loaded when the zone adds it to the loading queue.
	 * The page creates its own tiles and tells them to load when needed. 
	*/
	class PlanetaryPage : public PlanetaryLoadable
	{
	public:
		PlanetaryPage(PlanetarySceneManager *mgr);
		~PlanetaryPage();

		/// Initialises the base values of the page.
		void init(unsigned int zone, unsigned int pageX, unsigned int pageZ, PlanetaryZone *parent);
		/// Loads the actual data into the page and makes it ready for rendering.
		void load();
		/// Unloads the data, freeing up memory
		void unload();
		/// Uninitialises the page, clearing all the data that was created when it got initialised.
		void uninit();

		/// Shows or hides the page from rendering.
		/// @param do_it If set to true, show the page.
		void show(bool do_it);

		/// Returns the scene node this page is attached to.
		inline SceneNode *getSceneNode()
		{
			return mSceneNode;
		}

		/// Returns the current material of this page.
		inline MaterialPtr getMaterial()
		{
			return mRenderable->getMaterial();
		}
		
		/// Get parent of this page.
		inline PlanetaryZone* getParent()
		{
			return mParent;
		}

		/**
		* Update the paging of this page's tiles.
		* Checks for the current camera position and if the camera is too close, it loads the tiles and shows them instead.
		* @param cam The current camera viewing the scene.
		*/
		void updatePaging(Camera *cam);

		/// Sets the material of this page and it's tiles
		void setMaterial(MaterialPtr mat);

		/// Assign a page as the neighbour of this page
		void setNeighbour(NEIGHBOUR n, PlanetaryPage *p);

	private:
		bool mIsInit; /// True if the page has been initialised
		bool mVisible; /// True if this page, or its child tiles, are visible.

		/// Notify a neighbour, n implies the relationship this neighour has to the one getting notified: n = NORTH means that the neighour getting notified is north of the calling neighour
		void _notifyNeighbour(NEIGHBOUR n,PlanetaryPage *callingNeighour);

		/// Used by the zone to notify it self that it has changed render LOD and might need to add / remove joints
		void _notifySelf();

		/// Scene node for this page
		SceneNode *mSceneNode;

		/// Scene Manager Object
		PlanetarySceneManager *mSceneMgr;

		/// Parent Zone
		PlanetaryZone *mParent;

		/// LOD joints
		PlanetaryPageLODJoint *mLODJoints[4];

		/// Neighbours
		PlanetaryPage *mNeighbours[4];

		/// A renderable for this page, used for long distance LOD
		PlanetaryPageRenderable *mRenderable;

		// Page location
		unsigned int mZone; /// Parent Zone ID
		unsigned int mPageX; /// The X index of this page
		unsigned int mPageZ; /// The Z index of this page

		/// Tiles
		std::vector< std::vector< PlanetaryTile *> > mTiles;
	};
}

#endif
